/*
 * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package com.albert.iotcar;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.albert.View.SideSlideView;
import com.albert.WSMqtt.WSMqttCallback;
import com.albert.WSMqtt.WSMqttService;
import com.albert.iotcar.databinding.ActivityMainBinding;
import com.albert.pjsua2.MSG_TYPE;
import com.albert.pjsua2.MyApp;
import com.albert.pjsua2.SipManager;
import com.albert.pjsua2.VideoSurfaceHandler;
import com.albert.tool.NetConfigManager;
import com.google.android.material.appbar.MaterialToolbar;

import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.pjsip.pjsua2.AccountConfig;
import org.pjsip.pjsua2.CallInfo;
import org.pjsip.pjsua2.CallMediaInfo;
import org.pjsip.pjsua2.CallOpParam;
import org.pjsip.pjsua2.OnCallMediaEventParam;
import org.pjsip.pjsua2.StreamInfo;
import org.pjsip.pjsua2.VideoWindowInfo;
import org.pjsip.pjsua2.pjmedia_event_type;
import org.pjsip.pjsua2.pjmedia_orient;
import org.pjsip.pjsua2.pjsip_inv_state;
import org.pjsip.pjsua2.pjsip_role_e;
import org.pjsip.pjsua2.pjsip_status_code;

public class CallActivity extends AppCompatActivity implements Handler.Callback {
    private static final String TAG = "Yaogan";
    private WSMqttService wsMqttService;

    private String mqttReceiveId = "";
    public static Handler handler_;
    private final Handler handler = new Handler(this);
    private static CallInfo lastCallInfo;

    private VideoSurfaceHandler localVideoHandler;
    private VideoSurfaceHandler remoteVideoHandler;

    private MaterialToolbar toolbar;
    private final Handler barhandler = new Handler();
    private final Runnable hideToolbarRunnable = this::hideToolbar;
    private Boolean actionBarIsShow = false;
    private Boolean isSpeakerOn = false;

    private void showToolbar() {
        toolbar.animate()
                .translationY(0)
                .setDuration(150)
                .start();
        actionBarIsShow = true;
    }

    private void hideToolbar() {
        toolbar.animate()
                .translationY(-toolbar.getHeight() - getStatusBarHeight())
                .setDuration(150)
                .start();
        actionBarIsShow = false;
    }

    private int getStatusBarHeight() {
        int result = 0;
        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            result = getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }

    private ActivityMainBinding binding;

    private SideSlideView leftSideSlideView;
    private SideSlideView rightSideSlideView;
    private CallActivityMoveCar callActivityMoveCar;
    private CallActivityMoveArm callActivityMoveArm;
    private CallActivityMoveCamera callActivityMoveCamera;

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_call);
        binding = ActivityMainBinding.inflate(getLayoutInflater());

        toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowTitleEnabled(false);
//         给 Toolbar 增加状态栏高度的 padding，避免文字被遮住
        ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, insets) -> {
            int statusBarHeight = insets.getInsets(WindowInsetsCompat.Type.statusBars()).top;
            v.setPadding(0, statusBarHeight, 0, 0);
            return insets;
        });

        // 初始放到屏幕外
        toolbar.post(() -> toolbar.setTranslationY(-toolbar.getHeight() - getStatusBarHeight()));

        // 点击屏幕 -> 下拉显示，3秒后收回
        View contentView = findViewById(android.R.id.content);
        contentView.setOnClickListener(v -> {
            barhandler.removeCallbacks(hideToolbarRunnable);
            if (!actionBarIsShow) {
                showToolbar();
                barhandler.postDelayed(hideToolbarRunnable, 2000);
            } else {
                hideToolbar();
            }
        });
        ImageButton buttonHangup = findViewById(R.id.buttonHangup);
        buttonHangup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                hangupCall();
            }
        });

        SurfaceView surfaceInVideo = findViewById(R.id.surfaceIncomingVideo);
        SurfaceView surfacePreview = findViewById(R.id.surfacePreviewCapture);

        /* Avoid visible black boxes (blank video views) initially */
        if (SipManager.getInstance().currentCall == null || SipManager.getInstance().currentCall.vidWin == null) {
            surfaceInVideo.setVisibility(View.GONE);
            surfacePreview.setVisibility(View.GONE);
        }

        localVideoHandler = new VideoSurfaceHandler(surfacePreview.getHolder());
        remoteVideoHandler = new VideoSurfaceHandler(surfaceInVideo.getHolder());
        surfaceInVideo.getHolder().addCallback(remoteVideoHandler);
        surfacePreview.getHolder().addCallback(localVideoHandler);

        handler_ = handler;
        if (SipManager.getInstance().currentCall != null) {
            try {
                lastCallInfo = SipManager.getInstance().currentCall.getInfo();
                updateCallState(lastCallInfo);
            } catch (Exception e) {
                System.out.println(e);
            }
        } else {
            updateCallState(lastCallInfo);
        }

        mqttReceiveId = NetConfigManager.getConfig().mqttReceiveId;

        leftSideSlideView = findViewById(R.id.leftSlideView);
        rightSideSlideView = findViewById(R.id.rightSlideView);
        leftSideSlideView.setOnSlideStateCallBack(new SideSlideView.OnSlideStateCallBack() {
            @Override
            public void onSlideOpened() {
                callActivityMoveCar.setVisibility(View.GONE);
            }

            @Override
            public void onSlideClosed() {
                if (!rightSideSlideView.isSideViewOpen){
                    callActivityMoveCar.setVisibility(View.VISIBLE);
                }
            }
        });
        rightSideSlideView.setOnSlideStateCallBack(new SideSlideView.OnSlideStateCallBack() {
            @Override
            public void onSlideOpened() {
                callActivityMoveCar.setVisibility(View.GONE);
            }

            @Override
            public void onSlideClosed() {
                if (!leftSideSlideView.isSideViewOpen){
                    callActivityMoveCar.setVisibility(View.VISIBLE);
                }
            }
        });

        startMqttService();
        Intent intent = getIntent();
        Boolean pickUpCall = intent.getBooleanExtra("pickUpCall", false);
        if (pickUpCall) {
            acceptCall();
        }
    }

    /**
     * 开启Mqtt服务
     */
    public void startMqttService() {
        String mqttIP = NetConfigManager.getConfig().mqttIP;
        int mqttPort = NetConfigManager.getConfig().mqttPort;
        String mqttAccount = NetConfigManager.getConfig().mqttAccount;
        String mqttSubTopic = NetConfigManager.getConfig().mqttSubTopic;

//        if (mqttIP.isEmpty() || mqttAccount.isEmpty() || mqttSubTopic.isEmpty()) {
//            return;
//        }
        wsMqttService = new WSMqttService(
                this,
                "tcp://" + mqttIP + ":" + mqttPort,
                mqttAccount,
                mqttSubTopic,
                "BoardReceiveMsg", callback);

        callActivityMoveCar = findViewById(R.id.move_car_layout);
        callActivityMoveArm = findViewById(R.id.move_arm_layout);
        callActivityMoveCamera = findViewById(R.id.move_camera_layout);
        callActivityMoveCar.setMqttService(wsMqttService);
        callActivityMoveArm.setMqttService(wsMqttService);
        callActivityMoveCamera.setMqttService(wsMqttService);
    }

    private WSMqttCallback callback = (new WSMqttCallback() {
        @Override
        public void connectionLost(Throwable cause) {

        }

        @Override
        public void mqttConnectSuccess(IMqttToken asyncActionToken) {

        }

        @Override
        public void mqttConnectFailure(IMqttToken asyncActionToken, Throwable exception) {

        }

        @Override
        public void messageArrived(String topic, MqttMessage message) {

        }
    });

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        WindowManager wm;
        Display display;
        int rotation;
        int orient;

        wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
        display = wm.getDefaultDisplay();
        rotation = display.getRotation();
        System.out.println("Device orientation changed: " + rotation);

        switch (rotation) {
            case Surface.ROTATION_0:   // Portrait
                orient = pjmedia_orient.PJMEDIA_ORIENT_ROTATE_270DEG;
                break;
            case Surface.ROTATION_90:  // Landscape, home button on the right
                orient = pjmedia_orient.PJMEDIA_ORIENT_NATURAL;
                break;
            case Surface.ROTATION_180:
                orient = pjmedia_orient.PJMEDIA_ORIENT_ROTATE_90DEG;
                break;
            case Surface.ROTATION_270: // Landscape, home button on the left
                orient = pjmedia_orient.PJMEDIA_ORIENT_ROTATE_180DEG;
                break;
            default:
                orient = pjmedia_orient.PJMEDIA_ORIENT_UNKNOWN;
        }

        if (MyApp.ep != null && SipManager.getInstance().account != null) {
            try {
                AccountConfig cfg = SipManager.getInstance().account.cfg;
                int cap_dev = cfg.getVideoConfig().getDefaultCaptureDevice();
                MyApp.ep.vidDevManager().setCaptureOrient(cap_dev, orient, true);
            } catch (Exception e) {
                System.out.println(e);
            }
        }
    }

    private void setupIncomingVideoLayout() {
        try {
            StreamInfo si = SipManager.getInstance().currentCall.getStreamInfo(SipManager.getInstance().currentCall.vidGetStreamIdx());
            int w = (int) si.getVidCodecParam().getDecFmt().getWidth();
            int h = (int) si.getVidCodecParam().getDecFmt().getHeight();

            /* Adjust width to match the parent layout */
            RelativeLayout videoLayout = findViewById(R.id.bottom_layout);
            h = (int) ((double) videoLayout.getMeasuredWidth() / w * h);
            w = videoLayout.getMeasuredWidth();

            /* Also adjust height to match the parent layout */
            if (h > videoLayout.getMeasuredHeight()) {
                w = (int) ((double) videoLayout.getMeasuredHeight() / h * w);
                h = videoLayout.getMeasuredHeight();
            }
            System.out.println("Remote video size=" + w + "x" + h);

            /* Resize the remote video surface */
            SurfaceView surfaceInVideo = findViewById(R.id.surfaceIncomingVideo);

            DisplayMetrics metrics = new DisplayMetrics();
            Display display = getWindowManager().getDefaultDisplay();
            display.getMetrics(metrics);
            surfaceInVideo.setVisibility(View.VISIBLE);

            /* Put local preview always on top */
            if (SipManager.getInstance().currentCall.vidPrevStarted) {
                SurfaceView surfacePreview = findViewById(R.id.surfacePreviewCapture);
                surfacePreview.setVisibility(View.VISIBLE);
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public void setupVideoPreviewLayout() {
        /* Resize the preview video surface */
        try {
            int w, h;
            SurfaceView surfacePreview = findViewById(R.id.surfacePreviewCapture);
            VideoWindowInfo vwi = SipManager.getInstance().currentCall.vidPrev.getVideoWindow().getInfo();
            w = (int) vwi.getSize().getW();
            h = (int) vwi.getSize().getH();

            /* Adjust width to match the parent layout */
            RelativeLayout videoLayout = findViewById(R.id.bottom_layout);
            h = (int) ((double) videoLayout.getMeasuredWidth() / 2 / w * h);
            w = videoLayout.getMeasuredWidth() / 2;

            /* Also adjust height to match the parent layout */
            if (h > videoLayout.getMeasuredHeight() / 2) {
                w = (int) ((double) videoLayout.getMeasuredHeight() / 2 / h * w);
                h = videoLayout.getMeasuredHeight() / 2;
            }
            System.out.println("Preview video size=" + w + "x" + h);

            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(w, h);
            params.leftMargin = videoLayout.getMeasuredWidth() - w;
            params.topMargin = videoLayout.getMeasuredHeight() - h;
            surfacePreview.setLayoutParams(params);
            surfacePreview.setVisibility(View.VISIBLE);
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public void acceptCall() {
        CallOpParam prm = new CallOpParam();
        prm.setStatusCode(pjsip_status_code.PJSIP_SC_OK);
        try {
            SipManager.getInstance().currentCall.answer(prm);
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public void hangupCall() {
        localVideoHandler.resetVideoWindow();
        remoteVideoHandler.resetVideoWindow();

        handler_ = null;
        finish();

        if (SipManager.getInstance().currentCall != null) {
            CallOpParam prm = new CallOpParam();
            prm.setStatusCode(pjsip_status_code.PJSIP_SC_DECLINE);
            try {
                SipManager.getInstance().currentCall.hangup(prm);
            } catch (Exception e) {
                System.out.println(e);
            }
        }
    }

    public void speakerAction(View view) {
        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        ImageButton btn = (ImageButton) view;
        audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);

        int max = audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);
        audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, max, 0);

        isSpeakerOn = !isSpeakerOn;
        if (isSpeakerOn) {
            btn.setImageResource(R.drawable.ic_speaker_on);
            audioManager.setSpeakerphoneOn(true);
        } else {
            btn.setImageResource(R.drawable.ic_speaker_off);
            audioManager.setSpeakerphoneOn(false);
        }
    }

    @Override
    public boolean handleMessage(Message m) {
        if (m.what == MSG_TYPE.CALL_STATE) {
            lastCallInfo = (CallInfo) m.obj;
            if (lastCallInfo.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED) {
                localVideoHandler.resetVideoWindow();
                remoteVideoHandler.resetVideoWindow();
            }
            updateCallState(lastCallInfo);
        } else if (m.what == MSG_TYPE.CALL_MEDIA_STATE) {
            if (SipManager.getInstance().currentCall.vidWin != null) {
                /* Set capture orientation according to current
                 * device orientation.
                 */
                onConfigurationChanged(getResources().getConfiguration());
            }

            if (SipManager.getInstance().currentCall.vidPrev != null) {
                localVideoHandler.setVideoWindow(SipManager.getInstance().currentCall.vidPrev.getVideoWindow());
                setupVideoPreviewLayout();
            }

        } else if (m.what == MSG_TYPE.CALL_MEDIA_EVENT) {
            OnCallMediaEventParam prm = (OnCallMediaEventParam) m.obj;
            if (prm.getEv().getType() == pjmedia_event_type.PJMEDIA_EVENT_FMT_CHANGED && prm.getMedIdx() == SipManager.getInstance().currentCall.vidGetStreamIdx() &&
                    SipManager.getInstance().currentCall.vidWin != null) {
                CallMediaInfo cmi;
                try {
                    CallInfo ci = SipManager.getInstance().currentCall.getInfo();
                    cmi = ci.getMedia().get((int) prm.getMedIdx());
                } catch (Exception e) {
                    System.out.println(e);
                    return false;
                }
                remoteVideoHandler.setVideoWindow(cmi.getVideoWindow());
                setupIncomingVideoLayout();
            }
        } else {
            return false;
        }
        return true;
    }

    private void updateCallState(CallInfo ci) {
        TextView tvState = findViewById(R.id.textViewCallState);
        String call_state = "";

        if (ci == null) {
            tvState.setText("Call disconnected");
            return;
        }

        if (ci.getRole() == pjsip_role_e.PJSIP_ROLE_UAC) {
//            buttonAccept.setVisibility(View.GONE);
        }

        if (ci.getState() < pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED) {
            if (ci.getRole() == pjsip_role_e.PJSIP_ROLE_UAS) {
                call_state = "Incoming call..";
                /* Default button texts are already 'Accept' & 'Reject' */
            } else {
                call_state = ci.getStateText();
            }
        } else if (ci.getState() >= pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED) {
            call_state = ci.getStateText();
            if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_CONFIRMED) {
            } else if (ci.getState() == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED) {
                call_state = "Call disconnected: " + ci.getLastReason();
                hangupCall();
            }
        }
//获取远程设备Uri        ci.getRemoteUri()
        tvState.setText(call_state);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler_ = null;
        barhandler.removeCallbacks(hideToolbarRunnable);
    }
}

//    private static final long HIDE_DELAY_MILLIS = 2000; // 2秒后隐藏
//    private Handler barhandler = new Handler(Looper.getMainLooper());
//    private Runnable hideRunnable = new Runnable() {
//        @Override
//        public void run() {
//            ActionBar actionBar = getSupportActionBar();
//            if (actionBar != null) {
//                actionBar.hide();
//            }
//        }
//    };
//    private void showActionBarTemporarily() {
//        ActionBar actionBar = getSupportActionBar();
//        if (actionBar != null && !actionBar.isShowing()) {
//            actionBar.show();
//        }
//
//        barhandler.removeCallbacks(hideRunnable);
//        barhandler.postDelayed(hideRunnable, HIDE_DELAY_MILLIS);
//    }

//        // 初始隐藏 ActionBar
//        ActionBar actionBar = getSupportActionBar();
//        if (actionBar != null) {
//            actionBar.hide();
//        }
//
//        View rootView = findViewById(android.R.id.content);
//        rootView.setOnTouchListener(new View.OnTouchListener() {
//            @Override
//            public boolean onTouch(View v, MotionEvent event) {
//                if (event.getAction() == MotionEvent.ACTION_DOWN) {
//                    showActionBarTemporarily();
//                }
//                return false;
//            }
//        });

// 让布局延伸到状态栏
//        WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
//        getWindow().setStatusBarColor(Color.TRANSPARENT);

